<?php

/**
 * CCoreMimeMessage
 * CCoreMimeMessageCollection
 *
 * @author Usenko Timur <usenko.timur@gmail.com>
 * @package mime
 */

CCore::Using('base.datetime');
CCore::Using('mime.part');
CCore::Using('mime.message.attachment');
CCore::Using('mime.message.bodytext');
CCore::Using('mime.message.bodystructure');
CCore::Using('mime.emails');

/**
 * @package mime
 */
class CCoreMimeMessage extends CCoreMimePart
{
	/**
	 * @var CCoreMimeMessageBodyTextCollection
	 */
	public $BodyText;

	/**
	 * @var CCoreMimeMessageAttachmentsCollection
	 */
	public $Attachments;

	/**
	 * @return CCoreMimeMessage
	 */
	public function __construct()
	{
		parent::__construct();

		$this->Reset();
	}

	/**
	 * @return void
	 */
	public function Reset()
	{
		parent::Reset();
		
		$this->BodyText = new CCoreMimeMessageBodyTextCollection();
		$this->Attachments = new CCoreMimeMessageAttachmentsCollection();
	}

	/**
	 * @param string $sOutputCharset = C_MIME_CHARSET_UTF8
	 * @return string
	 */
	public function Subject($sOutputCharset = C_MIME_CHARSET_UTF8)
	{
		return $this->Headers->GetDecodedValueByName(C_MIME_HEADERS_SUBJECT, $sOutputCharset);
	}

	/**
	 * @return CCoreBaseDateTime
	 */
	public function RealDateAsObject()
	{
		$oDate = $this->ReceivedDateAsObject();
		if (null === $oDate)
		{
			$oDate = $this->DateAsObject();
		}
		return $oDate;
	}

	/**
	 * @return CCoreBaseDateTime
	 */
	public function DateAsObject()
	{
		$sResult = null;
		$sDateHeaderValue = $this->Headers->GetValueByName(C_MIME_HEADERS_DATE);
		if (0 < strlen($sDateHeaderValue))
		{
			$oDateTime = new CCoreBaseDateTime();
			$oDateTime->ParseFromRFC2822DateString($sDateHeaderValue);
			$sResult = $oDateTime;
		}
		return $sResult;
	}

	/**
	 * @return CCoreBaseDateTime
	 */
	public function ReceivedDateAsObject()
	{
		$sResult = null;
		$aReceivedHeaderValues = $this->Headers->GetValuesByName(C_MIME_HEADERS_RECEIVED);
		if (0 < count($aReceivedHeaderValues))
		{
			$sFirstReceivedHeaderValue = str_replace(array("\r", ';'), array('', "\n"), $aReceivedHeaderValues[0]);
			$aReceivedArray = explode("\n", $sFirstReceivedHeaderValue);
			foreach ($aReceivedArray as $sReceivedItem)
			{
				$sReceivedItem = trim($sReceivedItem);
				if (preg_match('/[\d]{4} [\d]{2}:[\d]{2}:[\d]{2} /', $sReceivedItem))
				{
					$oDateTime = new CCoreBaseDateTime();
					$oDateTime->ParseFromRFC2822DateString($sReceivedItem);
					$sResult = $oDateTime;
					break;
				}
			}
		}
		return $sResult;
	}

	/**
	 * @param CCoreBaseDateTime $oDateTime
	 * @param string $sFromat
	 * @param int $iTimeOffsetInSec = 0
	 * @return string
	 */
	public function DateObjToString($oDateTime, $sFromat, $iTimeOffsetInSec = 0)
	{
		if (is_a($oDateTime, 'CCoreBaseDateTime'))
		{
			return $oDateTime->SetTimeOffset($iTimeOffsetInSec)->ToFormatString($sFromat);
		}
		return '';
	}

	/**
	 * @param string $sOutputCharset = C_MIME_CHARSET_UTF8
	 * @return CCoreMimeEmail
	 */
	public function From($sOutputCharset = C_MIME_CHARSET_UTF8)
	{
		$sDecodedValue = $this->Headers->GetDecodedValueByName(C_MIME_HEADERS_FROM, $sOutputCharset);
		if (!empty ($sDecodedValue))
		{
			$oMimeEmail = new CCoreMimeEmail();
			$oMimeEmail->Parse($sDecodedValue);
			return $oMimeEmail;
		}
		return null;
	}

	/**
	 * @param string $sOutputCharset = C_MIME_CHARSET_UTF8
	 * @return CCoreMimeEmailCollection
	 */
	public function To($sOutputCharset = C_MIME_CHARSET_UTF8)
	{
		$sDecodedValue = $this->Headers->GetDecodedValueByName(C_MIME_HEADERS_TO, $sOutputCharset);
		if (!empty($sDecodedValue))
		{
			return new CCoreMimeEmailCollection($sDecodedValue);
		}
		return null;
	}

	/**
	 * @param string $sOutputCharset = C_MIME_CHARSET_UTF8
	 * @return CCoreMimeEmailCollection
	 */
	public function Cc($sOutputCharset = C_MIME_CHARSET_UTF8)
	{
		$sDecodedValue = $this->Headers->GetDecodedValueByName(C_MIME_HEADERS_CC, $sOutputCharset);
		if (!empty($sDecodedValue))
		{
			return new CCoreMimeEmailCollection($sDecodedValue);
		}
		return null;
	}

	/**
	 * @param string $sOutputCharset = C_MIME_CHARSET_UTF8
	 * @return CCoreMimeEmailCollection
	 */
	public function Bcc($sOutputCharset = C_MIME_CHARSET_UTF8)
	{
		$sDecodedValue = $this->Headers->GetDecodedValueByName(C_MIME_HEADERS_BCC, $sOutputCharset);
		if (!empty($sDecodedValue))
		{
			return new CCoreMimeEmailCollection($sDecodedValue);
		}
		return null;
	}

	/**
	 * @return bool
	 */
	public function HasAttachments()
	{
		if (0 < $this->Attachments->Count())
		{
			return true;
		}
		else
		{
			$sBoundaryHeaderValue = $this->Headers->GetBoundaryHeaderValue();
			if (!empty($sBoundaryHeaderValue))
			{
				$sContentTypeValue = strtolower($this->Headers->GetContentTypeValue());
				if (false !== strpos($sContentTypeValue, 'multipart/mixed'))
				{
					return true;
				}
				if (false !== strpos($sContentTypeValue, 'multipart/related'))
				{
					return true;
				}
				if (false !== strpos($sContentTypeValue, 'multipart/report'))
				{
					return true;
				}
			}
		}
		
		return false;
	}

	/**
	 * @param resource $rStreamHandle
	 * @param ICoreMimeCallbacks $oCallbackClass = null
	 * @return void
	 */
	public function ParseFromStream($rStreamHandle, ICoreMimeCallbacks $oCallbackClass = null)
	{
		parent::ParseFromStream($rStreamHandle, $oCallbackClass);

		$this->BodyText->Clear();
		$this->Attachments->Clear();

		foreach ($this->LineParts as /* @var $oMimePart CCoreMimePart */ &$oMimePart)
		{
			switch (true)
			{
				case $this->_isAttachmentMimePart($oMimePart):
					$this->Attachments->Add(new CCoreMimeMessageAttachment($oMimePart));
					break;
				case $this->_isTextMimePart($oMimePart):
					$this->BodyText->Add(new CCoreMimeMessageBodyText($oMimePart));
					break;
			}
		}
	}

	private function _isTextMimePart(CCoreMimePart &$oMimePart)
	{
		$sContentTypeFirstParamValue =
			trim(strtolower($oMimePart->Headers->GetValueByName(C_MIME_HEADERS_CONTENT_TYPE)));
		
		return (0 === strpos($sContentTypeFirstParamValue, 'text/'));
	}

	private function _isAttachmentMimePart(CCoreMimePart &$oMimePart)
	{
		if (0 < strlen($oMimePart->Headers->GetParamValueFromHeader(C_MIME_HEADERS_CONTENT_DISPOSITION, 'filename'))
			|| 0 < strlen($oMimePart->Headers->GetParamValueFromHeader(C_MIME_HEADERS_CONTENT_TYPE, 'name'))
			|| 3 < strlen($oMimePart->Headers->GetValueByName(C_MIME_HEADERS_CONTENT_ID)))
		{
			return true;
		}

		$sContentTypeHeaderValue = $oMimePart->Headers->GetValueByName(C_MIME_HEADERS_CONTENT_TYPE);
		$sContentDispositionHeaderValue = $oMimePart->Headers->GetValueByName(C_MIME_HEADERS_CONTENT_DISPOSITION);

		if (false !== strpos(strtolower($sContentTypeHeaderValue), 'message')
				|| false !== strpos(strtolower($sContentDispositionHeaderValue), 'attachment')
				|| false !== strpos(strtolower($sContentTypeHeaderValue), 'image'))
		{
			return true;
		}

		return false;
	}
}

/**
 * @package mime
 */
class CCoreMimeMessageCollection extends CCoreMimePartsCollection
{
	/**
	 * @return CCoreMimeMessageCollection
	 */
	public function __construct()
	{
		parent::__construct();
	}

	/**
	 * @param CCoreMimeMessage $oMimeMessage
	 * @return void
	 */
	public function Add(CCoreMimeMessage $oMimeMessage)
	{
		CCore::CheckTypes(array('$oMimeMessage'));

		parent::Add($oMimeMessage);
	}
}